<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="utf-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta
      name="viewport"
      content="width=device-width, initial-scale=1, maximum-scale=1, minimum-scale=1, user-scalable=no"
    />
    <meta
      name="description"
      content="Use image-based lighting to light a model."
    />
    <meta name="cesium-sandcastle-labels" content="Showcases" />
    <title>Cesium Demo</title>
    <script type="text/javascript" src="../Sandcastle-header.js"></script>
    <script
      type="text/javascript"
      src="../../../Build/CesiumUnminified/Cesium.js"
      nomodule
    ></script>
    <script type="module" src="../load-cesium-es6.js"></script>
  </head>
  <body
    class="sandcastle-loading"
    data-sandcastle-bucket="bucket-requirejs.html"
  >
    <style>
      @import url(../templates/bucket.css);
    </style>
    <div id="cesiumContainer" class="fullSize"></div>
    <div id="loadingOverlay"><h1>Loading...</h1></div>
    <div id="toolbar">
      <table>
        <tbody>
          <tr>
            <td>Luminance at Zenith</td>
            <td>
              <input
                type="range"
                min="0.0"
                max="2.0"
                step="0.01"
                data-bind="value: luminanceAtZenith, valueUpdate: 'input'"
              />
              <input
                type="text"
                size="4"
                data-bind="value: luminanceAtZenith"
              />
            </td>
          </tr>
        </tbody>
      </table>
    </div>
    <script id="cesium_sandcastle_script">
      function startup(Cesium) {
        "use strict";
        //Sandcastle_Begin
        const viewer = new Cesium.Viewer("cesiumContainer");

        if (!viewer.scene.specularEnvironmentMapsSupported) {
          window.alert(
            "This browser does not support specular environment maps."
          );
        }

        const environmentMapURL =
          "https://cesium.com/public/SandcastleSampleData/kiara_6_afternoon_2k_ibl.ktx2";
        const modelURL = "../../SampleData/models/Pawns/Pawns.glb";

        // This environment map was processed using Khronos's glTF IBL Sampler. To process your own:
        // 1 - Download and build the Khronos glTF IBL Sampler (https://github.com/KhronosGroup/glTF-IBL-Sampler).
        // 2 - Run `cli -inputPath /path/to/image.hdr -outCubeMap /path/to/output.ktx2`. Run `cli -h` for all options.

        // To generate the spherical harmonic coefficients below, use Google's Filament project:
        // 1 - Download the Filament release (https://github.com/google/filament/releases).
        // 2 - Run `cmgen --type=ktx --deploy=/path/to/output /path/to/image.hdr`. Other formats are also supported. Run `cmgen --help` for all options.
        // 3 - Take the generated coefficients and load them in CesiumJS as shown below.

        const L00 = new Cesium.Cartesian3(
          1.234709620475769,
          1.221461296081543,
          1.273156881332397
        );
        const L1_1 = new Cesium.Cartesian3(
          1.135921120643616,
          1.171217799186707,
          1.287644743919373
        );
        const L10 = new Cesium.Cartesian3(
          1.245193719863892,
          1.245591878890991,
          1.282818794250488
        );
        const L11 = new Cesium.Cartesian3(
          -1.106930732727051,
          -1.112522482872009,
          -1.153198838233948
        );
        const L2_2 = new Cesium.Cartesian3(
          -1.086226940155029,
          -1.079731941223145,
          -1.101912498474121
        );
        const L2_1 = new Cesium.Cartesian3(
          1.189834713935852,
          1.185906887054443,
          1.214385271072388
        );
        const L20 = new Cesium.Cartesian3(
          0.01778045296669,
          0.02013735473156,
          0.025313569232821
        );
        const L21 = new Cesium.Cartesian3(
          -1.086826920509338,
          -1.084611177444458,
          -1.111204028129578
        );
        const L22 = new Cesium.Cartesian3(
          -0.05241484940052,
          -0.048303380608559,
          -0.041960217058659
        );
        const coefficients = [L00, L1_1, L10, L11, L2_2, L2_1, L20, L21, L22];

        const height = 0.0;
        const hpr = new Cesium.HeadingPitchRoll(0.0, 0.0, 0.0);
        const origin = Cesium.Cartesian3.fromDegrees(
          -123.0744619,
          44.0503706,
          height
        );
        const modelMatrix = Cesium.Transforms.headingPitchRollToFixedFrame(
          origin,
          hpr
        );

        const model = viewer.scene.primitives.add(
          Cesium.Model.fromGltf({
            url: modelURL,
            modelMatrix: modelMatrix,
            minimumPixelSize: 128,
          })
        );

        model.readyPromise
          .then(function (model) {
            const camera = viewer.camera;

            // Zoom to model
            const controller = viewer.scene.screenSpaceCameraController;
            const r =
              2.0 * Math.max(model.boundingSphere.radius, camera.frustum.near);
            controller.minimumZoomDistance = r * 0.5;

            const center = Cesium.Matrix4.multiplyByPoint(
              model.modelMatrix,
              model.boundingSphere.center,
              new Cesium.Cartesian3()
            );
            const heading = Cesium.Math.toRadians(230.0);
            const pitch = Cesium.Math.toRadians(-20.0);
            camera.lookAt(
              center,
              new Cesium.HeadingPitchRange(heading, pitch, r * 2.0)
            );
            camera.lookAtTransform(Cesium.Matrix4.IDENTITY);

            model.sphericalHarmonicCoefficients = coefficients;
            model.specularEnvironmentMaps = environmentMapURL;

            // The viewModel tracks the state of our mini application.
            const viewModel = {
              luminanceAtZenith: model.luminanceAtZenith,
            };
            // Convert the viewModel members into knockout observables.
            Cesium.knockout.track(viewModel);

            // Bind the viewModel to the DOM elements of the UI that call for it.
            const toolbar = document.getElementById("toolbar");
            Cesium.knockout.applyBindings(viewModel, toolbar);

            function subscribeParameter(name) {
              Cesium.knockout
                .getObservable(viewModel, name)
                .subscribe(function (newValue) {
                  model[name] = newValue;
                });
            }

            subscribeParameter("luminanceAtZenith");

            Sandcastle.addToggleButton(
              "Use procedural environment lighting",
              false,
              function (checked) {
                if (!checked) {
                  model.sphericalHarmonicCoefficients = coefficients;
                  model.specularEnvironmentMaps = environmentMapURL;
                } else {
                  model.sphericalHarmonicCoefficients = undefined;
                  model.specularEnvironmentMaps = undefined;
                }
              }
            );
          })
          .catch(function (error) {
            window.alert(error);
          });
        //Sandcastle_End
        Sandcastle.finishedLoading();
      }
      if (typeof Cesium !== "undefined") {
        window.startupCalled = true;
        startup(Cesium);
      }
    </script>
  </body>
</html>
